import codec.PacketDecoder;
import codec.PacketEncoder;
import handler.LifeCyCleTestHandler;
import handler.Spliter;
import handler.login.LoginResponseHandler;
import handler.message.MessageResponseHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import protocol.packet.login.LoginRequest;
import protocol.packet.message.MessageRequest;
import utils.SessionUtil;

import java.util.Date;
import java.util.Scanner;
import java.util.concurrent.TimeUnit;

import static java.lang.Math.min;

public class NettyClient {
    public static void main(String[] args) throws InterruptedException {
        Bootstrap bootstrap = new Bootstrap();
        NioEventLoopGroup group = new NioEventLoopGroup();

        bootstrap.group(group)
                // 指定类型为NIO
                .channel(NioSocketChannel.class)
                // IO逻辑处理
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline()
                                .addLast(new Spliter())
                                .addLast(new PacketDecoder())
                                .addLast(new LoginResponseHandler())
                                .addLast(new MessageResponseHandler())
                                .addLast(new PacketEncoder());
                    }
                });
        connect(bootstrap, "127.0.0.1", 8000, 10);
    }

    private static void connect(Bootstrap bootstrap, String host, int port, int retry) {
        bootstrap.connect(host, port).addListener(future -> {
            if(future.isSuccess()) {
                System.out.println("连接成功");
                // 连接成功之后启动控制台线程
                Channel channel = ((ChannelFuture)future).channel();
                starConsoleThread(channel);
            } else if(retry == 0) {
                System.out.println("连接失败");
            } else {
                // 假设最多重连10次
                int order = 10 - retry + 1;
                // 重试的时间间隔
                int delay = 1 << min(order, 10);
                System.out.println(new Date() + ":连接失败，第" + order + "次重连");
                bootstrap.config().group().schedule(()->connect(bootstrap, host, port, retry - 1),
                        delay, TimeUnit.SECONDS);
            }
        });
    }

    private static void starConsoleThread(Channel channel) {
        Scanner sc = new Scanner(System.in);
        LoginRequest request = new LoginRequest();
        new Thread(() -> {
            while(!Thread.interrupted()) {
                if(!SessionUtil.hasLogin(channel)) {
                    System.out.print("输入用户名登录: ");
                    String username = sc.nextLine();
                    request.setUsername(username);
                    request.setPassword("123456");
                    channel.writeAndFlush(request);
                    waitForLoginResponse();
                } else {
                    String toUserId = sc.nextLine();
                    String msg = sc.nextLine();
                    channel.writeAndFlush(new MessageRequest(toUserId, msg));
                }
            }
        }).start();
    }

    private static void waitForLoginResponse() {
        try {
            Thread.sleep((2000));
        } catch (InterruptedException ignore) {

        }
    }
}
